#include "../config.h"

#include "strfuncs.h"
#include "application.h"
#include "command.h"
#include "keybind.h"

namespace gpyp {

//========================
// KeyBindEntry
void KeyBindEntry::on_load(conf::ConfParser &parser,
                           const char  *element_name,
                           const char **attribute_names,
                           const char **attribute_values) {
  if (get_element_depth() == 0 &&
      parser.get_document().version() < "3.6") {
    const char  *key = NULL, *mods = NULL;
    const char **name = attribute_names, **value = attribute_values;
    for(; *name && *value; ++name, ++value) {
      if      (!strcmp(*name, "key"))  key  = *value;
      else if (!strcmp(*name, "mods")) mods = *value;
    }
    if (key && mods) {
      uint key_p  = touint(key, 0);
      int  mods_p = toint(mods, -1);
      if (key_p && mods_p >= 0) {
        mods_p &= Gtk::AccelGroup::get_default_mod_mask();

        Glib::ustring name = AttributeAccel::name(key_p, (Gdk::ModifierType)mods_p);
        if (!name.empty()) accel_->on_load(name.c_str());
      }
    }
  }
  conf::Element::on_load(parser, element_name,
                         attribute_names, attribute_values);
}

KeyBindEntry::KeyBindEntry(const Glib::ustring &name) :
  conf::Element(name),
  accel_       (new AttributeAccel("accel", 0, (Gdk::ModifierType)0)),
  command_     ("command", "")
{
  add(accel_);
  add(command_);
}

//========================
// KeyBind
RefKeyBindEntry KeyBind::on_create_item(const Glib::ustring &name) {
  return RefKeyBindEntry(new KeyBindEntry(name));
}

RefKeyBindEntry KeyBind::add_item() {
  return conf::Collection<KeyBindEntry, KeyBind>::add_item();
}
RefKeyBindEntry KeyBind::add_item(guint key, Gdk::ModifierType mods,
                                  const Glib::ustring &command) {
  RefKeyBindEntry entry = add_item();
  entry->accel()->set(key, mods);
  entry->command() = command;
  return entry;
}

bool KeyBind::run(Application      &app,
                  guint             accel_key,
                  Gdk::ModifierType accel_mods,
                  SlotActivate      slot_activate) {
  accel_key   = gdk_keyval_to_lower(accel_key);
  accel_mods &= Gtk::AccelGroup::get_default_mod_mask();
  for(iterator iter = begin(); iter != end(); ++iter) {
    if (accel_key  == (*iter)->accel()->get_key() &&
        accel_mods == (*iter)->accel()->get_mods()) {
      CommandOpts opts;
      if (!slot_activate.empty()) slot_activate(opts);
      app.commandrunner().run(*(*iter)->command(), &opts);
      return true;
    }
  }
  for(std::list<RefKeyBind>::iterator iter = children_.begin();
      iter != children_.end(); ++iter) {
    if ((*iter)->run(app, accel_key, accel_mods, slot_activate)) {
      return true;
    }
  }
  return false;
}

KeyBind::KeyBind() :
  conf::Collection<KeyBindEntry, KeyBind>("key", "item")
{
}

}/*gpyp*/
